﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MMessaging.MessagingEx.Common;
using MMessaging.MessagingEx.Services;

namespace MMessaging.Address.Services
{
	/// <summary>
	/// Plug-In für einen MMessaging-Service.
	/// Sendet selbstständig in einem Intervall eine Alife-Message an alle.
	/// Setzt voraus, dass bei Start des Service die Message MServiceStartedMessage
	/// an den Service gesendet wird. Das ist bei der Service-Basisklasse 
	/// "MAddressServiceBase" bereits der Fall. Die Service-Basisklasse MAddressServiceBase
	/// verwendet dieses Plug-In bereits.
	/// </summary>
	/// <typeparam name="MESSAGETYPE"></typeparam>
	/// <typeparam name="ISALIFEMESSAGETYPE">
	/// Typ der Alife-Message - muss das Interface
	/// <code><![CDATA[
	/// IMAddressAlifeMessage
	/// ]]></code>
	/// implementieren.
	/// </typeparam>
	public class MServiceAddressPlugIn<MESSAGETYPE, ISALIFEMESSAGETYPE> : MAddressPlugInBase<MESSAGETYPE>
		where MESSAGETYPE : class
		where ISALIFEMESSAGETYPE : MESSAGETYPE, IMAddressAlifeMessage
	{
		#region types

		/// <summary>
		/// Delegate, der eine Message erzeugt, das eine Instanz der
		/// Klasse ISALIFEMESSAGETYPE erzeugt.
		/// </summary>
		/// <param name="intervallTime"></param>
		/// <param name="receiver"></param>
		/// <param name="sender"></param>
		/// <param name="sentTime"></param>
		/// <param name="messageID"></param>
		/// <returns></returns>
		public delegate ISALIFEMESSAGETYPE CreateIsAlifeMessageFunc(
			int intervallTime,
			MAddress receiver,
			MAddress sender,
			IEnumerable<MAddress> roles,
			DateTime sentTime,
			Guid messageID
			);

		#endregion

		#region private 

		private MAddress _senderAddress;
		private IEnumerable<MAddress> _roles;
		private int _intervalltimeOfAlifemessage;
		private CreateIsAlifeMessageFunc _createIsAlifeMessageFunc;

		#endregion

		#region constructor

		/// <summary>
		/// constructor
		/// </summary>
		/// <param name="intervalltimeOfAlifemessage">
		/// Intervallzeit, für das zyklische Senden der Alife-Message
		/// </param>
		/// <param name="createIsAlifeMessageFunc">
		/// Methode, die eine IsAlifemessage erzeugen kann.
		/// Z.B. MAddressIsAlifeMessage.CreateIsAlifeMessage
		/// <code><![CDATA[
		/// ISALIFEMESSAGETYPE CreateIsAlifeMessageFunc(
		///		int intervallTime,
		///		MAddress receiver,
		///		MAddress sender,
		///		IEnumerable<MAddress> roles,
		///		DateTime sentTime,
		///		Guid messageID	)
		/// ]]></code>
		/// </param>
		/// <param name="roles">
		/// Rollen des Service, der das Plug-In einbindet.
		/// </param>
		/// <param name="serviceAddress">
		/// Adresse des Service, der das Plug-In einbindet.
		/// </param>
		public MServiceAddressPlugIn(
			MAddress serviceAddress,
			IEnumerable<MAddress> roles,
			int intervalltimeOfAlifemessage,
			CreateIsAlifeMessageFunc createIsAlifeMessageFunc
			) : base()
		{
			_roles = roles;
			_createIsAlifeMessageFunc = createIsAlifeMessageFunc;
			_intervalltimeOfAlifemessage = intervalltimeOfAlifemessage;
			_senderAddress = serviceAddress;
		}

		#endregion

		#region overrides

		protected override void OnServiceStarted(IMTask<MESSAGETYPE> task)
		{
			while (!IsCanceling)
			{
				PostMessageFunc(_createIsAlifeMessageFunc(
					_intervalltimeOfAlifemessage,
					MDefaultAddress.BROADCAST,
					_senderAddress,
					_roles,
					DateTime.UtcNow,
					Guid.NewGuid()));

				task.SleepWithException(_intervalltimeOfAlifemessage);
			}
		}

		#endregion
	}
}
